package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Pattern;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.BeanCopierUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.StringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.exception.EventCallException;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.eventconfig.DeployedEventConfigDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.model.EventResponse;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowEventConfigRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowEventConfig;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowEventConfigExample;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowEventException;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowEventConfigDAO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 * @author lilh
 * @date 2021/2/26 14:52
 */
@Repository
@Slf4j
public class FlowEventConfigRepositoryImpl implements FlowEventConfigRepository {

    @Autowired
    private FlowEventConfigDAO eventConfigDAO;

    @Value("${flow.event.domainCheck.enable:false}")
    private Boolean isCheckUrl;                     //是否使用白名单检查

    @Value("${flow.event.domainCheck.whiteList:}")
    private String whiteList;                      //白名单信息

    @Autowired
    private RestTemplate restTemplate;


    @Override
    public boolean insertEventConfig(DeployedEventConfigDomain eventConfig) {
        FlowEventConfig entity = new FlowEventConfig();
        BeanCopierUtils.copyProperties(eventConfig, entity);
        entity.setGmtCreate(new Date());
        entity.setGmtModified(new Date());
        return eventConfigDAO.insert(entity) > 0;
    }

    @Override
    public DeployedEventConfigDomain getEventConfig(String deploymentId, String nodeCode, String eventType) {
        FlowEventConfigExample query = new FlowEventConfigExample();
        query.createCriteria().andDeploymentIdEqualTo(deploymentId)
                .andNodeCodeEqualTo(nodeCode)
                .andEventTypeEqualTo(eventType);
        List<FlowEventConfig> flowEventConfigs = eventConfigDAO.selectByExampleWithBLOBs(query);
        if (CollectionUtil.isNotEmpty(flowEventConfigs)) {
            FlowEventConfig flowEventConfig = flowEventConfigs.get(0);
            DeployedEventConfigDomain result = new DeployedEventConfigDomain();
            BeanCopierUtils.copyProperties(flowEventConfig, result);
            return result;
        }
        return null;
    }

    @Override
    public List<DeployedEventConfigDomain> getEventConfigList(String deploymentId, String nodeCode, String eventType) {
        List<DeployedEventConfigDomain> result = new ArrayList<>();
        FlowEventConfigExample query = new FlowEventConfigExample();
        query.createCriteria().andDeploymentIdEqualTo(deploymentId)
                .andNodeCodeEqualTo(nodeCode)
                .andEventTypeEqualTo(eventType);
        List<FlowEventConfig> flowEventConfigs = eventConfigDAO.selectByExampleWithBLOBs(query);
        if (CollectionUtil.isNotEmpty(flowEventConfigs)) {
            for (FlowEventConfig config : flowEventConfigs) {
                DeployedEventConfigDomain temp = new DeployedEventConfigDomain();
                BeanCopierUtils.copyProperties(config, temp);
                result.add(temp);
            }
        }
        return result;
    }
    @Override
    public List<DeployedEventConfigDomain> getEventConfigListByModelId(String modelId) {
        List<DeployedEventConfigDomain> result = new ArrayList<>();
        FlowEventConfigExample query = new FlowEventConfigExample();
        query.createCriteria().andModelIdEqualTo(modelId);
        List<FlowEventConfig> flowEventConfigs = eventConfigDAO.selectByExampleWithBLOBs(query);
        if (CollectionUtil.isNotEmpty(flowEventConfigs)) {
            for (FlowEventConfig config : flowEventConfigs) {
                DeployedEventConfigDomain temp = new DeployedEventConfigDomain();
                BeanCopierUtils.copyProperties(config, temp);
                result.add(temp);
            }
        }
        return result;
    }
    @Override
    public ResponseResult<String> checkUrl(String url){
        String result="";
        Boolean flag=false;

        if (!isCheckUrl){
            return ResponseResult.success(result);
        }
        if(StringUtils.isNotBlank(url)){
            Pattern pattern = Pattern.compile("^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\/])+(\\$\\{[A-Za-z0-9-~]+\\}[\\/]?)?$");
            if(pattern.matcher(url).matches()){
                flag=true;
                result="输入的url合法";
            }
            else{
                result="输入的url格式不合法";
            }
        }
        else{ result="输入的url不能为空"; }
        if(flag && isCheckUrl){
            List<String> wl=handleWhiteList(whiteList);
            if(isInWhiteList(wl,url)){
                result="输入的url合法且在白名单中";
                flag=true;
            }
            else{
                result="输入的url合法但不在白名单中";
                flag=false;
            }
        }
        if(flag){
            return ResponseResult.success(result);
        }
        else{
            return ResponseResult.fail(100,result);
        }
    };
    public List<String> handleWhiteList(String whiteList){
        List<String> result=new ArrayList<>();
        if(StringUtils.isNotBlank(whiteList)){
            String[] temp=whiteList.split(",");
            Collections.addAll(result,temp);
            return result;
        }
        return null;
    }
    public Boolean isInWhiteList(List<String> list,String url){
        Boolean flag=false;
        if(CollectionUtils.isEmpty(list)){
            return false;
        }
        String test="";
        for(int i=0;i<list.size();i++){
            if(StringUtils.isBlank(list.get(i))){
                continue;
            }
            test=list.get(i);
            test=test.replace("*","").trim();
            Pattern pattern=Pattern.compile(test);
            if(pattern.matcher(url).find()){
                flag=true;
                break;
            }
        }
        return flag;
    }
    @Override
    public EventResponse restTemplateRequest(String requestUrl, String requestBody) throws EventCallException {
        log.info(String.format("restTemplateRequest req: url = %s, requestBody = %s",requestUrl,requestBody));
        ResponseEntity<EventResponse> eventResponse = null;
        try {
            eventResponse = restTemplate.exchange(requestUrl, HttpMethod.POST,buildHttpEntity(requestBody), EventResponse.class);
        } catch (RestClientException e) {
            log.error("execute exchange error:",e);
            throw new EventCallException("事件接口调用异常："+e.getMessage());
        }
        if (Objects.nonNull(eventResponse)){
            if (!Objects.equals(org.apache.http.HttpStatus.SC_OK,eventResponse.getStatusCodeValue())){
                throw new EventCallException("事件接口调用失败");
            }else{
                log.info("call exchange success!");
            }
            log.info("restTemplateResponse:"+ JSON.toJSONString(eventResponse));
        }
        return eventResponse.getBody();
    }

    /**
     * 组织请求参数
     *
     * @param requestBody
     * @return
     */
    private HttpEntity<String> buildHttpEntity(String requestBody){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAcceptCharset(Collections.singletonList(Charset.forName("utf-8")));
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        return new HttpEntity(requestBody,headers);
    }
}
